package com.example.lin.customslidemenuview;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

public class SlideMenuView extends ViewGroup {

    public interface OnSlideCallback {
        void onOpen();

        void onClose();

        void onSlide(float slide);
    }

    private OnSlideCallback callback;

    public void setOnSlideCallback(OnSlideCallback callback) {
        this.callback = callback;
    }

    private final GestureDetectorCompat gestureDetectorCompat;
    //最大可以滑动的长度
    private int maxSlideLength;

    public SlideMenuView(Context context, AttributeSet attrs) {
        super(context, attrs);
        gestureDetectorCompat = new GestureDetectorCompat(context, listener);
        gestureDetectorCompat.setIsLongpressEnabled(false);
    }


    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    private static final int DEFAULT_WIDTH = 0;
    private static final int DEFAULT_HEIGHT = 0;

    private View slide;
    private View container;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (getChildCount() != 2)
            throw new IllegalArgumentException("SlideMenuView 有且只能有 2 个子View");
        slide = getChildAt(0);
        measureChild(slide, widthMeasureSpec, heightMeasureSpec);
        maxSlideLength = slide.getMeasuredWidth();
        container = getChildAt(1);
        measureChild(container, widthMeasureSpec, heightMeasureSpec);
        int resultWidth = getSize(DEFAULT_WIDTH, widthMeasureSpec);
        int resultHeight = getSize(DEFAULT_HEIGHT, heightMeasureSpec);
        setMeasuredDimension(resultWidth, resultHeight);
    }

    private int getSize(int defaultSize, int measureSpec) {
        int result = defaultSize;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        switch (specMode) {
            case MeasureSpec.AT_MOST:
                result = defaultSize;
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
        }
        return result;
    }


    private int containerLeft = 0;
    private int containerTop = 0;


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        int left = containerLeft, top = containerTop, right, bottom;
        right = left + container.getMeasuredWidth();
        bottom = top + container.getMeasuredHeight();


        container.layout(left, top, right, bottom);


        right = left / 2 + maxSlideLength / 2;
        left = right - slide.getMeasuredWidth();

        slide.layout(left, top, right, bottom);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        gestureDetectorCompat.onTouchEvent(event);
        if (isScroll) {
//            Log.d("ABC", "isScroll: " + isScroll);
            switch (event.getAction()) {
                case MotionEvent.ACTION_UP:
                    if (containerLeft != 0 && containerLeft != maxSlideLength) {
                        int end = containerLeft > maxSlideLength * 2 / 3 ? maxSlideLength : 0;
                        resetSlide(end);
                    }
                    break;
            }
        }
        return true;
    }

    private void resetSlide(int end) {
        long duration = 300 * Math.abs(end - containerLeft) / maxSlideLength;
        ValueAnimator valueAnimator = ValueAnimator.ofInt(containerLeft, end).setDuration(duration);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int f = (int) animation.getAnimatedValue();
                containerLeft = f;
                requestLayout();
                callbackSlide();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (callback != null) {
                    if (containerLeft == 0) {
                        callback.onClose();
                    } else {
                        callback.onOpen();
                    }
                }
            }
        });
        valueAnimator.start();
    }

    private boolean isScroll;

    private GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onDown(MotionEvent e) {
            isScroll = false;
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (velocityX > 1000 && containerLeft != maxSlideLength) {
                //打开
                isScroll = false;
                resetSlide(maxSlideLength);
            } else if (velocityX < -1000 && containerLeft != 0) {
                //关闭
                isScroll = false;
                resetSlide(0);
            }
//            Log.d("ABC", "onScroll: " + velocityX);
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            isScroll = true;
//            Log.d("ABC", "onScroll: " + distanceX);
            containerLeft -= distanceX;
            containerLeft = containerLeft <= 0 ? 0 : containerLeft >= maxSlideLength ? maxSlideLength : containerLeft;
            //重新 onLayout
            requestLayout();
            callbackSlide();
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    };

    private void callbackSlide() {
        if (callback != null) {
            float f = 1.0f * containerLeft / maxSlideLength;
            callback.onSlide(f);
        }
    }

}
